From: Felix Fietkau Date: Sun, 6 Jul 2025 16:50:00 +0000 (+0200) Subject: hostapd: add support for MLO interfaces in ucode X-Git-Url: http://git.openwrt.org/%22https:/collectd.org/%22http:/www.crowdsec.net//%22https%22/%22https:/collectd.org/%22http:/www.crowdsec.net/%22https%22?a=commitdiff_plain;h=816c2d86e749de23abd1803a292178e4ad38626a;p=openwrt%2Fopenwrt.git hostapd: add support for MLO interfaces in ucode MLO interface config is provided in a separate ubus call before adding regular per-phy interfaces. Preparation for full MLO support. Signed-off-by: Felix Fietkau --- diff --git a/package/network/config/wifi-scripts/files/usr/share/hostap/common.uc b/package/network/config/wifi-scripts/files/usr/share/hostap/common.uc index 31b526b6ae..caab14bcab 100644 --- a/package/network/config/wifi-scripts/files/usr/share/hostap/common.uc +++ b/package/network/config/wifi-scripts/files/usr/share/hostap/common.uc @@ -315,7 +315,7 @@ const phy_proto = { if (wdev.iftype == nl80211.const.NL80211_IFTYPE_AP_VLAN) continue; if (this.radio != null && wdev.vif_radio_mask != null && - !(wdev.vif_radio_mask & (1 << this.radio))) + wdev.vif_radio_mask != (1 << this.radio)) continue; mac_wdev[wdev.mac] = wdev; } diff --git a/package/network/services/hostapd/files/hostapd.uc b/package/network/services/hostapd/files/hostapd.uc index bdcba4880a..a28c282493 100644 --- a/package/network/services/hostapd/files/hostapd.uc +++ b/package/network/services/hostapd/files/hostapd.uc @@ -1,6 +1,6 @@ let libubus = require("ubus"); import { open, readfile } from "fs"; -import { wdev_remove, is_equal, vlist_new, phy_is_fullmac, phy_open, wdev_set_radio_mask } from "common"; +import { wdev_remove, is_equal, vlist_new, phy_is_fullmac, phy_open, wdev_set_radio_mask, wdev_set_up } from "common"; let ubus = libubus.connect(null, 60); @@ -50,13 +50,16 @@ hostapd.data.bss_info_fields = { owe_transition_ifname: true, }; +hostapd.data.mld = {}; + function iface_remove(cfg) { if (!cfg || !cfg.bss || !cfg.bss[0] || !cfg.bss[0].ifname) return; for (let bss in cfg.bss) - wdev_remove(bss.ifname); + if (!bss.mld_ap) + wdev_remove(bss.ifname); } function iface_gen_config(config, start_disabled) @@ -70,10 +73,12 @@ channel=${config.radio.channel} let bss = config.bss[i]; let type = i > 0 ? "bss" : "interface"; let nasid = bss.nasid ?? replace(bss.bssid, ":", ""); - + let bssid = bss.bssid; + if (bss.mld_ap) + bssid += "\nmld_addr=" + bss.mld_bssid; str += ` ${type}=${bss.ifname} -bssid=${bss.bssid} +bssid=${bssid} ${join("\n", bss.data)} nas_identifier=${nasid} `; @@ -142,6 +147,9 @@ function iface_add(phy, config, phy_status) function iface_config_macaddr_list(config) { let macaddr_list = {}; + for (let name, mld in hostapd.data.mld) + if (mld.macaddr) + macaddr_list[mld.macaddr] = -1; for (let i = 0; i < length(config.bss); i++) { let bss = config.bss[i]; if (!bss.default_macaddr) @@ -154,8 +162,11 @@ function iface_config_macaddr_list(config) function iface_update_supplicant_macaddr(phydev, config) { let macaddr_list = []; - for (let i = 0; i < length(config.bss); i++) - push(macaddr_list, config.bss[i].bssid); + for (let name, mld in hostapd.data.mld) + if (mld.macaddr) + push(macaddr_list, mld.macaddr); + for (let bss in config.bss) + push(macaddr_list, bss.bssid); ubus.defer("wpa_supplicant", "phy_set_macaddr_list", { phy: phydev.name, radio: phydev.radio ?? -1, @@ -178,13 +189,15 @@ function __iface_pending_next(pending, state, ret, data) iface_update_supplicant_macaddr(phydev, config); return "create_bss"; case "create_bss": - let err = phydev.wdev_add(bss.ifname, { - mode: "ap", - radio: phydev.radio, - }); - if (err) { - hostapd.printf(`Failed to create ${bss.ifname} on phy ${phy}: ${err}`); - return null; + if (!bss.mld_ap) { + let err = phydev.wdev_add(bss.ifname, { + mode: "ap", + radio: phydev.radio, + }); + if (err) { + hostapd.printf(`Failed to create ${bss.ifname} on phy ${phy}: ${err}`); + return null; + } } pending.call("wpa_supplicant", "phy_status", { @@ -550,6 +563,10 @@ function iface_reload_config(name, phydev, config, old_config) let cur_config = config.bss[i]; let prev_config = old_config.bss[prev]; + if (prev_config.force_reload) { + delete prev_config.force_reload; + continue; + } let prev_bss = get_config_bss(name, old_config, prev); if (!prev_bss) @@ -606,7 +623,8 @@ function iface_reload_config(name, phydev, config, old_config) let ifname = old_config.bss[i].ifname; hostapd.printf(`Remove bss '${ifname}' on phy '${name}'`); prev_bss.delete(); - wdev_remove(ifname); + if (!old_config.bss[i].mld_ap) + wdev_remove(ifname); } // Step 4: rename preserved interfaces, use temporary name on duplicates @@ -737,17 +755,78 @@ function iface_reload_config(name, phydev, config, old_config) return true; } +function bss_check_mld(phydev, iface_name, bss) +{ + if (!bss.ifname) + return; + + let mld_data = hostapd.data.mld[bss.ifname]; + if (!mld_data || !mld_data.ifname || !mld_data.macaddr) + return; + + bss.mld_bssid = mld_data.macaddr; + mld_data.iface[iface_name] = true; + if (mld_data.has_wdev) + return true; + + hostapd.printf(`Create MLD interface ${bss.ifname} on phy ${phydev.name}, radio mask: ${mld_data.radio_mask}`); + let err = phydev.wdev_add(bss.ifname, { + mode: "ap", + macaddr: mld_data.macaddr, + radio_mask: mld_data.radio_mask, + }); + wdev_set_up(bss.ifname, true); + if (err) { + hostapd.printf(`Failed to create MLD ${bss.ifname} on phy ${phydev.name}: ${err}`); + delete mld_data.iface[iface_name]; + return; + } + + mld_data.has_wdev = true; + + return true; +} + +function iface_check_mld(phydev, name, config) +{ + phydev = phy_open(phydev.phy); + + for (let mld_name, mld_data in hostapd.data.mld) + delete mld_data.iface[name]; + + for (let i = 0; i < length(config.bss); i++) { + let bss = config.bss[i]; + if (!bss.mld_ap) + continue; + + if (!bss_check_mld(phydev, name, bss)) { + hostapd.printf(`Skip MLD interface ${name} on phy ${phydev.name}`); + splice(config.bss, i--, 1); + } + } + + for (let mld_name, mld_data in hostapd.data.mld) { + if (length(mld_data.iface) > 0) + continue; + + hostapd.printf(`Remove MLD interface ${mld_name}`); + wdev_remove(mld_name); + delete mld_data.has_wdev; + } +} + +function iface_config_remove(name, old_config) +{ + hostapd.remove_iface(name); + return iface_remove(old_config); +} + function iface_set_config(name, config) { let old_config = hostapd.data.config[name]; hostapd.data.config[name] = config; - if (!config) { - hostapd.remove_iface(name); - return iface_remove(old_config); - } - let phy = config.phy; let phydev = phy_open(phy, config.radio_idx); if (!phydev) { @@ -755,6 +834,11 @@ function iface_set_config(name, config) return false; } + config.orig_bss = [ ...config.bss ]; + iface_check_mld(phydev, name, config); + if (!length(config.bss)) + return iface_config_remove(name, old_config); + try { let ret = iface_reload_config(name, phydev, config, old_config); if (ret) { @@ -787,10 +871,6 @@ function config_add_bss(config, name) function iface_load_config(phy, radio, filename) { - let f = open(filename, "r"); - if (!f) - return null; - if (radio < 0) radio = null; @@ -804,6 +884,10 @@ function iface_load_config(phy, radio, filename) orig_file: filename, }; + let f = open(filename, "r"); + if (!f) + return config; + let bss; let line; while ((line = rtrim(f.read("line"), "\n")) != null) { @@ -847,6 +931,9 @@ function iface_load_config(phy, radio, filename) if (val[0] == "nas_identifier") bss.nasid = val[1]; + if (val[0] == "mld_ap") + bss[val[0]] = int(val[1]); + if (val[0] == "bss") { bss = config_add_bss(config, val[1]); continue; @@ -901,6 +988,134 @@ function bss_config(bss_name) { } } +function mld_rename_bss(data, name) +{ + if (data.ifname == name) + return true; + + // TODO: handle rename gracefully + return false; +} + +function mld_add_bss(name, data, phy_list, i) +{ + let config = data.config; + if (!config.phy) + return; + + wdev_remove(name); + let phydev = phy_list[config.phy]; + if (!phydev) { + phydev = phy_open(config.phy, 0); + if (!phydev) + return; + + let macaddr_list = {}; + let phy_config = hostapd.data.config[phy_name(config.phy, 0)]; + if (phy_config) + macaddr_list = iface_config_macaddr_list(phy_config); + iface_macaddr_init(phydev, data.config, macaddr_list); + + phy_list[config.phy] = phydev; + } + + data.macaddr = config.macaddr; + if (!data.macaddr) { + data.macaddr = phydev.macaddr_next(); + data.default_macaddr = true; + } + + let radio_mask = 0; + for (let r in config.radios) + if (r != null) + radio_mask |= 1 << r; + + data.radio_mask = radio_mask; + data.ifname = name; +} + +function mld_find_matching_config(list, config) +{ + for (let name, data in list) + if (is_equal(data.config, config)) + return name; +} + +function mld_reload_interface(name) +{ + let config = hostapd.data.config[name]; + if (!config) + return; + + config = { ...config }; + config.bss = config.orig_bss; + + iface_set_config(name, config); +} + +function mld_set_config(config) +{ + let prev_mld = { ...hostapd.data.mld }; + let new_mld = {}; + let phy_list = {}; + let new_config = !length(prev_mld); + + hostapd.printf(`Set MLD config: ${keys(config)}`); + + // find renamed/new interfaces + for (let name, data in config) { + let prev = mld_find_matching_config(prev_mld, data); + if (prev) { + let data = prev_mld[prev]; + if (mld_rename_bss(data, name)) { + new_mld[name] = data; + delete prev_mld[prev]; + continue; + } + } + + new_mld[name] = { + config: data, + iface: {}, + }; + } + + let reload_iface = {}; + for (let name, data in prev_mld) { + delete hostapd.data.mld[name]; + + if (!data.ifname) + continue; + + for (let iface, bss_list in hostapd.bss) { + if (!bss_list[name]) + continue; + reload_iface[iface] = true; + } + } + + for (let name in reload_iface) + mld_reload_interface(name); + + for (let name, data in prev_mld) { + if (data.ifname) + hostapd.printf(`Remove MLD interface ${name}`); + wdev_remove(name); + } + + // add new interfaces + hostapd.data.mld = new_mld; + for (let name, data in new_mld) + mld_add_bss(name, data, phy_list); + + if (!new_config) + return; + + hostapd.printf(`Reload all interfaces`); + for (let name in hostapd.data.config) + mld_reload_interface(name); +} + let main_obj = { reload: { args: { @@ -988,6 +1203,31 @@ let main_obj = { return ret; }) }, + mld_set: { + args: { + config: {} + }, + call: ex_wrap(function(req) { + if (!req.args.config) + return libubus.STATUS_INVALID_ARGUMENT; + + mld_set_config(req.args.config); + + return { + pid: hostapd.getpid() + }; + }) + }, + config_reset: { + args: { + }, + call: ex_wrap(function(req) { + for (let name in hostapd.data.config) + iface_set_config(name); + mld_set_config({}); + return 0; + }) + }, config_set: { args: { phy: "", diff --git a/package/network/services/hostapd/patches/190-hostapd-Fix-hostapd-crash-if-setup-a-iface-with-.patch b/package/network/services/hostapd/patches/190-hostapd-Fix-hostapd-crash-if-setup-a-iface-with-.patch new file mode 100644 index 0000000000..d05f272afe --- /dev/null +++ b/package/network/services/hostapd/patches/190-hostapd-Fix-hostapd-crash-if-setup-a-iface-with-.patch @@ -0,0 +1,46 @@ +From c14e53ea013415a29e9c493e9dacafb6dc5b31ee Mon Sep 17 00:00:00 2001 +From: Michael-CY Lee +Date: Fri, 8 Nov 2024 10:20:03 +0800 +Subject: [PATCH] hostapd: Fix hostapd crash if setup a iface with a link bss failed + +The crash occurs while some link bsses is traversing all the links by using +for_each_mld_link(), and hostapd access to the link bss which is already +been freed. + +If hostapd setup a link bss failed, the link should be removed from +its hostapd_mld. However, the function hostapd_bss_link_deinit +doesn't remove the link bss correctly if it is the first bss and +hapd->drv_priv is null. Therefore we should refator the remove iface flow +as hostapd_remove_iface (used in wifi down cmd). + +There are some cases that setup a bss may fail (e.g. afc query failed) or +trigger channel switch while hostapd is setting up other links. +The failed link would be add into hostapd_mld while driver_init(). + +Signed-off-by: Allen Ye +Signed-off-by: Michael-CY Lee +Signed-off-by: Felix Fietkau +--- + src/ap/hostapd.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/src/ap/hostapd.c ++++ b/src/ap/hostapd.c +@@ -3878,6 +3878,7 @@ int hostapd_add_iface(struct hapd_interf + } + + if (hostapd_setup_interface(hapd_iface)) { ++ hostapd_bss_link_deinit(hapd_iface->bss[0]); + hostapd_deinit_driver( + hapd_iface->bss[0]->driver, + hapd_iface->bss[0]->drv_priv, +@@ -5135,6 +5136,9 @@ int hostapd_mld_remove_link(struct hosta + if (!mld) + return -1; + ++ if (!hapd->link.next) ++ return 0; ++ + dl_list_del(&hapd->link); + mld->num_links--; + diff --git a/package/network/services/hostapd/patches/191-hostapd-add-support-for-specifying-the-link-id-in-th.patch b/package/network/services/hostapd/patches/191-hostapd-add-support-for-specifying-the-link-id-in-th.patch new file mode 100644 index 0000000000..fa44875aa6 --- /dev/null +++ b/package/network/services/hostapd/patches/191-hostapd-add-support-for-specifying-the-link-id-in-th.patch @@ -0,0 +1,58 @@ +From: Felix Fietkau +Date: Thu, 3 Jul 2025 11:22:26 +0200 +Subject: [PATCH] hostapd: add support for specifying the link id in the config + +Makes it easier to dynamically manage links for a MLD at run time. + +Signed-off-by: Felix Fietkau +--- + +--- a/hostapd/config_file.c ++++ b/hostapd/config_file.c +@@ -4934,6 +4934,8 @@ static int hostapd_config_fill(struct ho + conf->punct_acs_threshold = val; + } else if (os_strcmp(buf, "mld_ap") == 0) { + bss->mld_ap = !!atoi(pos); ++ } else if (os_strcmp(buf, "mld_link_id") == 0) { ++ bss->mld_link_id = atoi(pos); + } else if (os_strcmp(buf, "mld_addr") == 0) { + if (hwaddr_aton(pos, bss->mld_addr)) { + wpa_printf(MSG_ERROR, "Line %d: Invalid mld_addr", +--- a/src/ap/ap_config.c ++++ b/src/ap/ap_config.c +@@ -177,6 +177,10 @@ void hostapd_config_defaults_bss(struct + bss->pasn_comeback_after = 10; + bss->pasn_noauth = 1; + #endif /* CONFIG_PASN */ ++ ++#ifdef CONFIG_IEEE80211BE ++ bss->mld_link_id = -1; ++#endif + } + + +--- a/src/ap/ap_config.h ++++ b/src/ap/ap_config.h +@@ -967,6 +967,8 @@ struct hostapd_bss_config { + /* The AP's MLD MAC address within the AP MLD */ + u8 mld_addr[ETH_ALEN]; + ++ s8 mld_link_id; ++ + #ifdef CONFIG_TESTING_OPTIONS + /* + * If set indicate the AP as disabled in the RNR element included in the +--- a/src/ap/hostapd.c ++++ b/src/ap/hostapd.c +@@ -3105,7 +3105,10 @@ struct hostapd_iface * hostapd_alloc_ifa + #ifdef CONFIG_IEEE80211BE + static void hostapd_bss_alloc_link_id(struct hostapd_data *hapd) + { +- hapd->mld_link_id = hapd->mld->next_link_id++; ++ if (hapd->conf->mld_link_id >= 0) ++ hapd->mld_link_id = hapd->conf->mld_link_id; ++ else ++ hapd->mld_link_id = hapd->mld->next_link_id++; + wpa_printf(MSG_DEBUG, "AP MLD: %s: Link ID %d assigned.", + hapd->mld->name, hapd->mld_link_id); + } diff --git a/package/network/services/hostapd/patches/300-noscan.patch b/package/network/services/hostapd/patches/300-noscan.patch index 6d97691855..314f0eff1b 100644 --- a/package/network/services/hostapd/patches/300-noscan.patch +++ b/package/network/services/hostapd/patches/300-noscan.patch @@ -18,7 +18,7 @@ Subject: [PATCH] Add noscan, no_ht_coex config options } else if (os_strcmp(buf, "ht_capab") == 0) { --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h -@@ -1105,6 +1105,8 @@ struct hostapd_config { +@@ -1107,6 +1107,8 @@ struct hostapd_config { int ht_op_mode_fixed; u16 ht_capab; diff --git a/package/network/services/hostapd/patches/600-ubus_support.patch b/package/network/services/hostapd/patches/600-ubus_support.patch index 0368726c81..b66d61bad5 100644 --- a/package/network/services/hostapd/patches/600-ubus_support.patch +++ b/package/network/services/hostapd/patches/600-ubus_support.patch @@ -159,7 +159,7 @@ probe/assoc/auth requests via object subscribe. if (iface->is_no_ir) { hostapd_set_state(iface, HAPD_IFACE_NO_IR); -@@ -3527,6 +3532,7 @@ void hostapd_interface_deinit_free(struc +@@ -3530,6 +3535,7 @@ void hostapd_interface_deinit_free(struc (unsigned int) iface->conf->num_bss); driver = iface->bss[0]->driver; drv_priv = iface->bss[0]->drv_priv; diff --git a/package/network/services/hostapd/patches/601-ucode_support.patch b/package/network/services/hostapd/patches/601-ucode_support.patch index ec25cd4084..a5aa2e6a79 100644 --- a/package/network/services/hostapd/patches/601-ucode_support.patch +++ b/package/network/services/hostapd/patches/601-ucode_support.patch @@ -113,6 +113,15 @@ as adding/removing interfaces. hostapd_ubus_free_bss(hapd); accounting_deinit(hapd); hostapd_deinit_wpa(hapd); +@@ -625,7 +628,7 @@ void hostapd_free_hapd_data(struct hosta + * If the BSS being removed is the first link, the next link becomes the first + * link. + */ +-static void hostapd_bss_link_deinit(struct hostapd_data *hapd) ++void hostapd_bss_link_deinit(struct hostapd_data *hapd) + { + #ifdef CONFIG_IEEE80211BE + int i; @@ -737,6 +740,7 @@ void hostapd_cleanup_iface_partial(struc static void hostapd_cleanup_iface(struct hostapd_iface *iface) { @@ -139,7 +148,47 @@ as adding/removing interfaces. { struct hostapd_bss_config *conf = hapd->conf; u8 ssid[SSID_MAX_LEN + 1]; -@@ -1518,6 +1522,8 @@ setup_mld: +@@ -1434,7 +1438,13 @@ static int hostapd_setup_bss(struct host + + if (!first || first == -1) { + u8 *addr = hapd->own_addr; ++ bool use_existing = first == -1; + ++#ifdef CONFIG_IEEE80211BE ++ if (hapd->conf->mld_ap) { ++ addr = NULL; ++ } else ++#endif /* CONFIG_IEEE80211BE */ + if (!is_zero_ether_addr(conf->bssid)) { + /* Allocate the configured BSSID. */ + os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN); +@@ -1469,6 +1479,7 @@ static int hostapd_setup_bss(struct host + hapd->mld_link_id, hapd->conf->iface); + goto setup_mld; + } ++ use_existing = true; + } + #endif /* CONFIG_IEEE80211BE */ + +@@ -1477,7 +1488,7 @@ static int hostapd_setup_bss(struct host + conf->iface, addr, hapd, + &hapd->drv_priv, force_ifname, if_addr, + conf->bridge[0] ? conf->bridge : NULL, +- first == -1)) { ++ use_existing)) { + wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID=" + MACSTR ")", MAC2STR(hapd->own_addr)); + hapd->interface_added = 0; +@@ -1500,7 +1511,7 @@ static int hostapd_setup_bss(struct host + + #ifdef CONFIG_IEEE80211BE + setup_mld: +- if (hapd->conf->mld_ap && !first) { ++ if (hapd->conf->mld_ap && first != 1) { + wpa_printf(MSG_DEBUG, + "MLD: Set link_id=%u, mld_addr=" MACSTR + ", own_addr=" MACSTR, +@@ -1518,6 +1529,8 @@ setup_mld: } #endif /* CONFIG_IEEE80211BE */ @@ -148,7 +197,16 @@ as adding/removing interfaces. if (conf->wmm_enabled < 0) conf->wmm_enabled = hapd->iconf->ieee80211n | hapd->iconf->ieee80211ax; -@@ -2516,7 +2522,7 @@ static int hostapd_owe_iface_iter2(struc +@@ -1843,7 +1856,7 @@ int hostapd_set_acl(struct hostapd_data + } + + +-static int hostapd_set_ctrl_sock_iface(struct hostapd_data *hapd) ++int hostapd_set_ctrl_sock_iface(struct hostapd_data *hapd) + { + #ifdef CONFIG_IEEE80211BE + int ret; +@@ -2516,7 +2529,7 @@ static int hostapd_owe_iface_iter2(struc #endif /* CONFIG_OWE */ @@ -157,7 +215,7 @@ as adding/removing interfaces. { #ifdef CONFIG_OWE /* Check whether the enabled BSS can complete OWE transition mode -@@ -2986,7 +2992,7 @@ hostapd_alloc_bss_data(struct hostapd_if +@@ -2986,7 +2999,7 @@ hostapd_alloc_bss_data(struct hostapd_if } @@ -166,7 +224,16 @@ as adding/removing interfaces. { if (!hapd) return; -@@ -4070,7 +4076,8 @@ int hostapd_remove_iface(struct hapd_int +@@ -3194,7 +3207,7 @@ fail: + } + + +-static void hostapd_cleanup_unused_mlds(struct hapd_interfaces *interfaces) ++void hostapd_cleanup_unused_mlds(struct hapd_interfaces *interfaces) + { + #ifdef CONFIG_IEEE80211BE + struct hostapd_mld *mld, **all_mld; +@@ -4074,7 +4087,8 @@ int hostapd_remove_iface(struct hapd_int hapd_iface = interfaces->iface[i]; if (hapd_iface == NULL) return -1; @@ -213,16 +280,24 @@ as adding/removing interfaces. void *owner; char *config_fname; struct hostapd_config *conf; -@@ -787,6 +794,8 @@ struct hostapd_iface * hostapd_init(stru +@@ -787,11 +794,16 @@ struct hostapd_iface * hostapd_init(stru struct hostapd_iface * hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy, const char *config_fname, int debug); ++int hostapd_set_ctrl_sock_iface(struct hostapd_data *hapd); +int hostapd_setup_bss(struct hostapd_data *hapd, int first, bool start_beacon); ++void hostapd_bss_link_deinit(struct hostapd_data *hapd); +void hostapd_bss_deinit(struct hostapd_data *hapd); void hostapd_bss_setup_multi_link(struct hostapd_data *hapd, struct hapd_interfaces *interfaces); void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, -@@ -817,6 +826,7 @@ hostapd_switch_channel_fallback(struct h + int reassoc); + void hostapd_interface_deinit_free(struct hostapd_iface *iface); ++void hostapd_cleanup_unused_mlds(struct hapd_interfaces *interfaces); + int hostapd_enable_iface(struct hostapd_iface *hapd_iface); + int hostapd_reload_iface(struct hostapd_iface *hapd_iface); + int hostapd_reload_bss_only(struct hostapd_data *bss); +@@ -817,6 +829,7 @@ hostapd_switch_channel_fallback(struct h void hostapd_cleanup_cs_params(struct hostapd_data *hapd); void hostapd_periodic_iface(struct hostapd_iface *iface); int hostapd_owe_trans_get_info(struct hostapd_data *hapd); diff --git a/package/network/services/hostapd/patches/701-reload_config_inline.patch b/package/network/services/hostapd/patches/701-reload_config_inline.patch index 236337979a..b91ff62e05 100644 --- a/package/network/services/hostapd/patches/701-reload_config_inline.patch +++ b/package/network/services/hostapd/patches/701-reload_config_inline.patch @@ -8,7 +8,7 @@ as adding/removing interfaces. --- a/hostapd/config_file.c +++ b/hostapd/config_file.c -@@ -4981,7 +4981,14 @@ struct hostapd_config * hostapd_config_r +@@ -4983,7 +4983,14 @@ struct hostapd_config * hostapd_config_r int errors = 0; size_t i; @@ -58,7 +58,7 @@ as adding/removing interfaces. return NULL; --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c -@@ -3380,8 +3380,13 @@ hostapd_interface_init_bss(struct hapd_i +@@ -3400,8 +3400,13 @@ hostapd_interface_init_bss(struct hapd_i } } diff --git a/package/network/services/hostapd/patches/720-iface_max_num_sta.patch b/package/network/services/hostapd/patches/720-iface_max_num_sta.patch index 5dfe839e5a..f0e3da9f59 100644 --- a/package/network/services/hostapd/patches/720-iface_max_num_sta.patch +++ b/package/network/services/hostapd/patches/720-iface_max_num_sta.patch @@ -25,7 +25,7 @@ full device, e.g. in order to deal with hardware/driver limitations } else if (os_strcmp(buf, "extended_key_id") == 0) { --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h -@@ -1069,6 +1069,8 @@ struct hostapd_config { +@@ -1071,6 +1071,8 @@ struct hostapd_config { unsigned int track_sta_max_num; unsigned int track_sta_max_age; @@ -79,7 +79,7 @@ full device, e.g. in order to deal with hardware/driver limitations { --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h -@@ -828,6 +828,7 @@ void hostapd_periodic_iface(struct hosta +@@ -831,6 +831,7 @@ void hostapd_periodic_iface(struct hosta int hostapd_owe_trans_get_info(struct hostapd_data *hapd); void hostapd_owe_update_trans(struct hostapd_iface *iface);; void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx); diff --git a/package/network/services/hostapd/patches/770-radius_server.patch b/package/network/services/hostapd/patches/770-radius_server.patch index d6fdb167f6..fdf5fed397 100644 --- a/package/network/services/hostapd/patches/770-radius_server.patch +++ b/package/network/services/hostapd/patches/770-radius_server.patch @@ -29,7 +29,7 @@ handle reload. #ifndef CONFIG_NO_HOSTAPD_LOGGER static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, -@@ -834,6 +835,11 @@ int main(int argc, char *argv[]) +@@ -838,6 +839,11 @@ int main(int argc, char *argv[]) if (os_program_init()) return -1; diff --git a/package/network/services/hostapd/patches/780-Implement-APuP-Access-Point-Micro-Peering.patch b/package/network/services/hostapd/patches/780-Implement-APuP-Access-Point-Micro-Peering.patch index 9528900e46..271b88c7c0 100644 --- a/package/network/services/hostapd/patches/780-Implement-APuP-Access-Point-Micro-Peering.patch +++ b/package/network/services/hostapd/patches/780-Implement-APuP-Access-Point-Micro-Peering.patch @@ -53,7 +53,7 @@ Hotfix-by: Sebastian Gottschall https://github.com/mirror/dd-wrt/commit/0c3001a6 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c -@@ -4974,6 +4974,15 @@ static int hostapd_config_fill(struct ho +@@ -4976,6 +4976,15 @@ static int hostapd_config_fill(struct ho bss->mld_indicate_disabled = atoi(pos); #endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_IEEE80211BE */ @@ -71,7 +71,7 @@ Hotfix-by: Sebastian Gottschall https://github.com/mirror/dd-wrt/commit/0c3001a6 "Line %d: unknown configuration item '%s'", --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h -@@ -982,6 +982,35 @@ struct hostapd_bss_config { +@@ -984,6 +984,35 @@ struct hostapd_bss_config { int mbssid_index; bool spp_amsdu; diff --git a/package/network/services/hostapd/src/src/ap/ucode.c b/package/network/services/hostapd/src/src/ap/ucode.c index d3eadba15a..cbe2ee9506 100644 --- a/package/network/services/hostapd/src/src/ap/ucode.c +++ b/package/network/services/hostapd/src/src/ap/ucode.c @@ -201,6 +201,49 @@ bss_reload_vlans(struct hostapd_data *hapd, struct hostapd_bss_config *bss) return 0; } +static void +__uc_hostapd_bss_stop(struct hostapd_data *hapd) +{ + struct hostapd_iface *iface = hapd->iface; + + if (!hapd->started) + return; + + hostapd_bss_deinit_no_free(hapd); + hostapd_drv_stop_ap(hapd); + hostapd_bss_link_deinit(hapd); + +#ifdef CONFIG_IEEE80211BE + if (hapd == iface->bss[0]) + hostapd_if_link_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface, + hapd->mld_link_id); +#endif + + hostapd_free_hapd_data(hapd); +} + +static int +__uc_hostapd_bss_start(struct hostapd_data *hapd) +{ + struct hostapd_iface *iface = hapd->iface; + bool first = hapd == iface->bss[0]; + int ret; + + if (hapd->started) + return 0; + +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap) + first = false; +#endif + + ret = hostapd_setup_bss(hapd, first, true); + hostapd_neighbor_set_own_report(hapd); + hostapd_owe_update_trans(iface); + + return ret; +} + static uc_value_t * uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs) { @@ -241,12 +284,10 @@ uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs) swap_field(ssid.wpa_psk_file); ret = bss_reload_vlans(hapd, bss); - goto done; + goto free; } - hostapd_bss_deinit_no_free(hapd); - hostapd_drv_stop_ap(hapd); - hostapd_free_hapd_data(hapd); + __uc_hostapd_bss_stop(hapd); old_bss = hapd->conf; for (i = 0; i < iface->conf->num_bss; i++) @@ -258,13 +299,9 @@ uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs) if (hapd == iface->bss[0]) memcpy(hapd->own_addr, hapd->conf->bssid, ETH_ALEN); - hostapd_setup_bss(hapd, hapd == iface->bss[0], true); - hostapd_neighbor_set_own_report(hapd); + ret = __uc_hostapd_bss_start(hapd); hostapd_ucode_update_interfaces(); - hostapd_owe_update_trans(iface); -done: - ret = 0; free: hostapd_config_free(conf); out: @@ -326,8 +363,13 @@ uc_hostapd_bss_delete(uc_vm_t *vm, size_t nargs) hostapd_bss_deinit(hapd); hostapd_remove_iface_bss_conf(iface->conf, hapd->conf); hostapd_config_free_bss(hapd->conf); +#ifdef CONFIG_IEEE80211BE + if (hapd->mld) + hapd->mld->refcount--; +#endif os_free(hapd); + hostapd_cleanup_unused_mlds(iface->interfaces); hostapd_ucode_update_interfaces(); return NULL; @@ -365,7 +407,12 @@ uc_hostapd_iface_add_bss(uc_vm_t *vm, size_t nargs) #ifdef CONFIG_IEEE80211BE os_strlcpy(hapd->ctrl_sock_iface, hapd->conf->iface, sizeof(hapd->ctrl_sock_iface)); + if (hapd->conf->mld_ap) { + hostapd_bss_setup_multi_link(hapd, iface->interfaces); + hostapd_set_ctrl_sock_iface(hapd); + } #endif + if (interfaces->ctrl_iface_init && interfaces->ctrl_iface_init(hapd) < 0) goto free_hapd; @@ -673,6 +720,7 @@ uc_hostapd_bss_rename(uc_vm_t *vm, size_t nargs) { struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss"); uc_value_t *ifname_arg = uc_fn_arg(0); + uc_value_t *skip_rename = uc_fn_arg(1); char prev_ifname[IFNAMSIZ + 1]; struct sta_info *sta; const char *ifname; @@ -688,9 +736,11 @@ uc_hostapd_bss_rename(uc_vm_t *vm, size_t nargs) if (interfaces->ctrl_iface_deinit) interfaces->ctrl_iface_deinit(hapd); - ret = hostapd_drv_if_rename(hapd, WPA_IF_AP_BSS, NULL, ifname); - if (ret) - goto out; + if (!ucv_is_truish(skip_rename)) { + ret = hostapd_drv_if_rename(hapd, WPA_IF_AP_BSS, NULL, ifname); + if (ret) + goto out; + } for (sta = hapd->sta_list; sta; sta = sta->next) { char cur_name[IFNAMSIZ + 1], new_name[IFNAMSIZ + 1];